/**
 * $Id: CurveShape.java,v 1.14 2011-01-04 12:04:04 david Exp $
 * Copyright (c) 2009-2010, David Benson, Gaudenz Alder
 */
package com.kg.rails.component.editor.shape;

import com.kg.rails.component.editor.canvas.Graphics2DCanvas;
import com.kg.rails.component.editor.util.Constants;
import com.kg.rails.component.editor.util.Curve;
import com.kg.rails.component.editor.util.EditorLine;
import com.kg.rails.component.editor.util.EditorPoint;
import com.kg.rails.component.editor.view.CellState;

import java.awt.*;
import java.util.List;
import java.util.Map;

public class CurveShape extends ConnectorShape {
    /**
     * Cache of the points between which drawing straight lines views as a
     * curve
     */
    protected Curve curve;

    /**
     *
     */
    public CurveShape() {
        this(new Curve());
    }

    /**
     *
     */
    public CurveShape(Curve curve) {
        this.curve = curve;
    }

    /**
     *
     */
    public Curve getCurve() {
        return curve;
    }

    /**
     *
     */
    public void paintShape(Graphics2DCanvas canvas, CellState state) {
        Object keyStrokeHint = canvas.getGraphics().getRenderingHint(
                RenderingHints.KEY_STROKE_CONTROL);
        canvas.getGraphics().setRenderingHint(
                RenderingHints.KEY_STROKE_CONTROL,
                RenderingHints.VALUE_STROKE_PURE);

        super.paintShape(canvas, state);

        canvas.getGraphics().setRenderingHint(
                RenderingHints.KEY_STROKE_CONTROL, keyStrokeHint);
    }

    /**
     *
     */
    protected void paintPolyline(Graphics2DCanvas canvas,
                                 List<EditorPoint> points, Map<String, Object> style) {
        double scale = canvas.getScale();
        validateCurve(points, scale, style);

        canvas.paintPolyline(curve.getCurvePoints(Curve.CORE_CURVE), false);
    }

    /**
     * Forces underlying curve to a valid state
     *
     * @param points
     */
    public void validateCurve(List<EditorPoint> points, double scale,
                              Map<String, Object> style) {
        if (curve == null) {
            curve = new Curve(points);
        } else {
            curve.updateCurve(points);
        }

        curve.setLabelBuffer(scale * Constants.DEFAULT_LABEL_BUFFER);
    }

    /**
     * Hook to override creation of the vector that the marker is drawn along
     * since it may not be the same as the vector between any two control
     * points
     *
     * @param points     the guide points of the connector
     * @param source     whether the marker is at the source end
     * @param markerSize the scaled maximum length of the marker
     * @return a line describing the vector the marker should be drawn along
     */
    protected EditorLine getMarkerVector(List<EditorPoint> points, boolean source,
                                         double markerSize) {
        double curveLength = curve.getCurveLength(Curve.CORE_CURVE);
        double markerRatio = markerSize / curveLength;
        if (markerRatio >= 1.0) {
            markerRatio = 1.0;
        }

        if (source) {
            EditorLine sourceVector = curve.getCurveParallel(Curve.CORE_CURVE,
                    markerRatio);
            return new EditorLine(sourceVector.getX(), sourceVector.getY(),
                    points.get(0));
        } else {
            EditorLine targetVector = curve.getCurveParallel(Curve.CORE_CURVE,
                    1.0 - markerRatio);
            int pointCount = points.size();
            return new EditorLine(targetVector.getX(), targetVector.getY(),
                    points.get(pointCount - 1));
        }
    }
}
